#ifndef _THREAD_HPP_
#define _THREAD_HPP_

#include <string>
#include <vector>

#include "base.hpp"

namespace mina
{
	namespace thread
	{
		enum
		{
			iThreadSingleQueue = 0,
			iThreadMultipleQueue = 1
		};

		class Thread 
		{
			public :
				Thread(const char * name = "NonNameThread");
				virtual ~Thread();

				int start();

				std::string name() const { return _name; }

				int index() const { return _index; }
				void index(int idx) { _index = idx; }
				pthread_t id() const { return _id; }

			protected :
				virtual void run() = 0;

			private :
				static void * run(void * arg)
				{
					Thread * pThis = reinterpret_cast<Thread*>(arg);
					pThis->run();
					return 0;
				}

			private :
				bool _start_flag;
				int  _index;
				std::string _name;

				pthread_t _id;

				DECL_LOGGER(logger);
		};

		template <typename _RequestType, typename _ResponseType, 
				 template <class> class _QueueType, int _Pattern = iThreadSingleQueue>
					 class ThreadPool
					 {
						 public :
							 typedef _RequestType RequestType;
							 typedef _ResponseType ResponseType;
							 typedef _QueueType<RequestType> RequestQueue;
							 typedef RequestQueue* RequestQueuePtr;
							 typedef _QueueType<ResponseType> ResponseQueue;
							 typedef ResponseQueue* ResponseQueuePtr;

						 public :
							 ThreadPool(const char * name = "NonNameThreadPool");
							 ~ThreadPool()
							 {
								 std::vector<Thread*>::iterator iter = _thread_vec.begin();
								 for (; iter != _thread_vec.end(); ++ iter)
								 {
									 SAFE_DELETE(*iter);
								 }
								 _thread_vec.clear();

								 SAFE_DELETE(_response_queue);

								 typename std::vector<RequestQueuePtr>::iterator iter2 = _request_queue_vec.begin();
								 for (; iter2 != _request_queue_vec.end(); ++ iter2)
								 {
									 SAFE_DELETE(*iter2);
								 }
							 }

							 int add_thread(Thread * pThread);

							 void start()
							 {
								 std::vector<Thread*>::iterator iter = _thread_vec.begin();
								 for (; iter != _thread_vec.end(); ++ iter)
								 {
									 (*iter)->start();
								 }
							 }

						 public :
							 void put_request(const RequestType & request)
							 {
								 single_assert();
								 _request_queue_vec[0]->put(request);
							 }

							 template <typename _Hash>
								 void put_request(const RequestType & request, _Hash hash_func)
								 {
									 multiple_assert();
									 int index = hash_func(request, _request_queue_vec.size());
									 assert(index >= 0 && index < int(_request_queue_vec.size()));
									 _request_queue_vec[index]->put(request);
								 }

							 void get_request(RequestType & request)
							 {
								 single_assert();
								 _request_queue_vec[0]->get(request);
							 }

							 void get_request(int index, RequestType & requestr)
							 {
								 multiple_assert();
								 _request_queue_vec[index]->get(requestr);
							 }

							 void put_response(const ResponseType & response)
							 {
								 _response_queue->put(response);
							 }
							 void get_response(ResponseType & response)
							 {
								 _response_queue->get(response);
							 }

							 /// @NOTICE this function just use for debug log
							 size_t request_size() 
							 {
								 single_assert();
								 return _request_queue_vec[0]->size();
							 }

							 /// @NOTICE this function just use for debug log
							 size_t request_size(int index) 
							 {
								 multiple_assert();
								 return _request_queue_vec[index]->size();
							 }

							 /// @NOTICE this function just use for debug log
							 size_t response_size() 
							 {
								 return _response_queue->size();
							 }

							 /// @NOTICE this function just use for debug log
							 bool request_empty() 
							 {
								 single_assert();
								 return _request_queue_vec[0]->empty();
							 }

							 /// @NOTICE this function just use for debug log
							 bool request_empty(int index) 
							 {
								 multiple_assert();
								 return _request_queue_vec[index]->empty();
							 }

							 /// @NOTICE this function just use for debug log
							 bool response_empty() 
							 {
								 return _response_queue->empty();
							 }

						 private :
							 void single_assert()
							 {
								 assert(iThreadSingleQueue == _Pattern);
							 }

							 void multiple_assert()
							 {
								 assert(iThreadMultipleQueue == _Pattern);
							 }
						 private :
							 std::string _name;
							 std::vector<Thread*> _thread_vec;
							 std::vector<RequestQueuePtr> _request_queue_vec;
							 ResponseQueuePtr _response_queue;
					 };

		template <typename _RequestType, 
				 typename _ResponseType, 
				 template <class> class _QueueType,
				 int _Pattern>
					 ThreadPool<_RequestType,
				 _ResponseType,
				 _QueueType,
				 _Pattern>::ThreadPool(const char * name)
				 {
					 _name = name;
					 _request_queue_vec.clear();

					 if (iThreadSingleQueue == _Pattern)
					 {
						 _request_queue_vec.push_back(new RequestQueue);
					 }

					 _response_queue = new ResponseQueue;
				 }

		template <typename _RequestType, 
				 typename _ResponseType, 
				 template <class> class _QueueType,
				 int _Pattern>
					 int ThreadPool<_RequestType,
				 _ResponseType,
				 _QueueType,
				 _Pattern>::add_thread(Thread * pThread)
				 {
					 if (iThreadMultipleQueue == _Pattern)
					 {
						 RequestQueuePtr queue = new RequestQueue;
						 _request_queue_vec.push_back(queue);
					 }

					 int idx = _thread_vec.size();
					 pThread->index(idx);
					 _thread_vec.push_back(pThread);

					 return idx;
				 }
	}
}

#endif

